package com.tripleying.dogend.dnfipm.model;

import com.jfoenix.controls.JFXAlert;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXDialogLayout;
import com.jfoenix.controls.JFXToggleButton;
import com.tripleying.dogend.dnfipm.App;
import com.tripleying.dogend.dnfipm.controller.MainController;
import com.tripleying.dogend.dnfipm.util.MessageUtil;
import com.tripleying.dogend.dnfipm.util.NPKUtil;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.text.Font;
import javafx.stage.FileChooser;
import javafx.stage.Modality;

/**
 * 补丁类
 * @author Dogend
 */
public class NPKItem{
    
    // 补丁名（不带后缀）
    private String name;
    // 补丁后缀（.npk或.NPK）
    private String suffix;
    // 启用状态的补丁文件
    private File enableFile;
    // 禁用状态的补丁文件
    private File disableFile;
    // 启用状态的补丁文件名
    private String enableName;
    // 禁用状态的补丁文件名
    private String disableName;
    // 补丁状态
    private boolean status;
    // 补丁是否有效
    private final boolean validate;
    // 切换状态按钮
    private final JFXToggleButton switchButton;
    private final JFXButton addPreviewButton;
    private final JFXButton previewButton;
    // 编辑按钮
    private final JFXButton editButton;
    // 删除按钮
    private final JFXButton deleteButton;
    private static final JFXAlert preview;
    private static final Label previewHeader;
    private static final ImageView iv;
    
    static {
        preview = new JFXAlert(App.getStage());
        preview.initModality(Modality.APPLICATION_MODAL);
        preview.setOverlayClose(false);
        preview.setHideOnEscape(false);
        JFXDialogLayout layout = new JFXDialogLayout();
        layout.getStylesheets().add("styles/scroll.css");
        layout.setPrefWidth(600);
        preview.setContent(layout);
        previewHeader = new Label("");
        previewHeader.setFont(new Font(20));
        layout.setHeading(previewHeader);
        ScrollPane sp = new ScrollPane();
        sp.setPadding(new Insets(5, 5, 5, 5));
        sp.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
        sp.setMaxHeight(400);
        iv = new ImageView();
        iv.setFitWidth(542);
        iv.setPreserveRatio(true);
        iv.setSmooth(true);
        sp.setContent(iv);
        layout.setBody(sp);
        JFXButton btn = new JFXButton("关闭");
        btn.getStyleClass().add("closeBtn");
        btn.setFont(new Font(16));
        btn.setOnAction(e -> preview.hideWithAnimation());
        layout.setActions(btn);
    }
    
    public NPKItem(File file){
        String fname = file.getName();
        if(NPKUtil.filenameCheck(fname)){
            validate = true;
            switchButton = new JFXToggleButton();
            switchButton.setAlignment(Pos.CENTER_LEFT);
            switchButton.setPrefWidth(280);
            switchButton.setMaxWidth(280);
            if(fname.endsWith(".NPK") || fname.endsWith(".npk")){
                status = true;
                enableName = fname;
                disableName = fname+".disable";
            }else{
                status = false;
                disableName = fname;
                enableName = fname.substring(0,fname.length()-8);
            }
            name = enableName.substring(0, enableName.length()-4);
            suffix = enableName.substring(enableName.length()-4);
            switchButton.setText(name);
            switchButton.setSelected(status);
            enableFile = new File(App.getFolder(), enableName);
            disableFile = new File(App.getFolder(), disableName);
            switchButton.setOnAction(e -> {
                if(switchButton.isSelected()){
                    enableNPK();
                }else{
                    disableNPK();
                    MainController.getInstance().updateSearchNPK(this);
                }
                MainController.getInstance().updateListTitle();
            });
            addPreviewButton = new JFXButton("设置预览");
            addPreviewButton.setAlignment(Pos.CENTER);
            addPreviewButton.setPrefWidth(75);
            addPreviewButton.setPrefHeight(25);
            addPreviewButton.getStyleClass().add("editBtn");
            addPreviewButton.setOnAction(e -> this.addPreviewNPK());
            previewButton = new JFXButton("预览");
            previewButton.setAlignment(Pos.CENTER);
            previewButton.setPrefWidth(50);
            previewButton.setPrefHeight(25);
            previewButton.getStyleClass().add("editBtn");
            previewButton.setOnAction(e -> this.previewNPK());
            editButton = new JFXButton("改名");
            editButton.setAlignment(Pos.CENTER);
            editButton.setPrefWidth(50);
            editButton.setPrefHeight(25);
            editButton.getStyleClass().add("editBtn");
            editButton.setOnAction(e -> this.renameFile());
            deleteButton = new JFXButton("删除");
            deleteButton.setAlignment(Pos.CENTER);
            deleteButton.setPrefWidth(50);
            deleteButton.setPrefHeight(25);
            deleteButton.getStyleClass().add("deleteBtn");
        }else{
            validate = false;
            switchButton = null;
            addPreviewButton = null;
            previewButton = null;
            editButton = null;
            deleteButton = null;
        }
    }
    
    public NPKItem(String fname){
        validate = true;
        switchButton = null;
        addPreviewButton = null;
        previewButton = null;
        editButton = null;
        deleteButton = null;
        if(!NPKUtil.filenameCheck(fname)) fname = "(补丁管理工具导入)"+fname;
        if(fname.endsWith(".NPK") || fname.endsWith(".npk")){
            status = true;
            enableName = fname;
            disableName = fname+".disable";
        }else{
            status = false;
            disableName = fname;
            enableName = fname.substring(0,fname.length()-8);
        }
        name = enableName.substring(0, enableName.length()-4);
        suffix = enableName.substring(enableName.length()-4);
        enableFile = new File(App.getFolder(), enableName);
        disableFile = new File(App.getFolder(), disableName);
    }
    
    public String getName(){
        return name;
    }
    
    public JFXToggleButton getSwitchButton(){
        return switchButton;
    }
    
    public JFXButton getAddPreviewButton() {
        return addPreviewButton;
    }

    public JFXButton getPreviewButton() {
        return previewButton;
    }

    public JFXButton getEditButton() {
        return editButton;
    }
    
    public JFXButton getDeleteButton(){
        return deleteButton;
    }
    
    public void enableNPK(){
        if(disableFile.exists()){
            disableFile.renameTo(enableFile);
        }
        updateStatus();
        if(switchButton!=null) switchButton.setSelected(status);
    }
    
    public void disableNPK(){
        if(enableFile.exists()){
            enableFile.renameTo(disableFile);
        }
        updateStatus();
        if(switchButton!=null) switchButton.setSelected(status);
    }
    
    public File getEnableFile(){
        return enableFile;
    }
    
    public File getDisableFile(){
        return disableFile;
    }
    
    private void addPreviewNPK(){
        FileChooser fc = new FileChooser();
        fc.getExtensionFilters().add(new FileChooser.ExtensionFilter("所有图片", "*.*"));
        fc.setTitle("请选择图片");
        File img = fc.showOpenDialog(App.getStage());
        if(img!=null && img.exists()){
            try{
                File npk = enableFile.exists()?enableFile:disableFile;
                if(!npk.exists()){
                    MessageUtil.alertSimpleMessage("添加失败", "补丁文件不存在", "关闭");
                    return;
                }
                try (FileInputStream is = new FileInputStream(img)) {
                    Image image = new Image(is);
                    if(image.isError()){
                        MessageUtil.alertSimpleMessage("添加失败", "读取图片失败", "关闭");
                        return;
                    }
                }
                try (FileInputStream is = new FileInputStream(img);RandomAccessFile raf = new RandomAccessFile(npk, "rw")) {
                    byte[] flag_byte = new byte[16];
                    raf.read(flag_byte);
                    if(!new String(flag_byte).contains("NeoplePack_Bill")){
                        MessageUtil.alertSimpleMessage("添加失败", "软件在线授权式补丁无法添加补丁预览图", "关闭");
                        return;
                    }
                    long length = raf.length();
                    raf.seek(length-18);
                    byte[] flagb = new byte[18];
                    raf.read(flagb);
                    String flag = new String(flagb);
                    if("Dogend NPK Preview".equals(flag)){
                        raf.seek(length-26);
                        int offset = raf.readInt();
                        raf.setLength(offset);
                        length = offset;
                        raf.seek(length);
                    }
                    int offset = (int)length;
                    byte[] buffer = new byte[1024];
                    int size = 0;
                    int len = 0;
                    while((len = is.read(buffer)) != -1){
                        raf.write(buffer);
                        size += len;
                    }
                    raf.writeInt(offset);
                    raf.writeInt(size);
                    raf.write("Dogend NPK Preview".getBytes());
                    MessageUtil.alertSimpleMessage("添加完成", "添加预览图完成, 请尝试预览一下", "关闭");
                }
            }catch(Exception e){
                e.printStackTrace();
                MessageUtil.alertSimpleMessage("添加失败", "读取图片失败或补丁文件可能被占用", "关闭");
            }
        }
    }
    
    private void previewNPK(){
        previewHeader.setText("预览补丁: "+name);
        iv.setImage(null);
        File file = enableFile.exists()?enableFile:disableFile;
        if(file.exists()){
            try {
                try(RandomAccessFile raf = new RandomAccessFile(file, "r")){
                    long length = raf.length();
                    raf.seek(length-18);
                    byte[] flagb = new byte[18];
                    raf.read(flagb);
                    String flag = new String(flagb);
                    if("Dogend NPK Preview".equals(flag)){
                        raf.seek(length-26);
                        int offset = raf.readInt();
                        int size = raf.readInt();
                        raf.seek(offset);
                        byte[] data = new byte[size];
                        raf.read(data);
                        ByteArrayInputStream bais = new ByteArrayInputStream(data);
                        Image img = new Image(bais);
                        if(!img.isError()){
                            NPKItem.previewImage(img);
                        }else{
                            MessageUtil.alertSimpleMessage("预览失败", "读取补丁内存储的预览图失败, 可能不是图片", "关闭");
                        }
                    }else{
                        Image img = NPKUtil.previewNPK(file);
                        if(img!=null && !img.isError()){
                            if(img.getHeight()>5 && img.getWidth()>5){
                                NPKItem.previewImage(img);
                                return;
                            }
                        }
                        MessageUtil.alertSimpleMessage("预览失败", "补丁内未存储预览图, 尝试读取内部图片失败", "关闭");
                    }
                }
            } catch (IOException ex) {
                ex.printStackTrace();
                MessageUtil.alertSimpleMessage("预览失败", "读取图片失败或补丁文件可能被占用", "关闭");
            }
        }
    }
    
    private static void previewImage(Image image){
        try{
            iv.setImage(image);
            preview.show();
        }catch(Exception ex){
            MessageUtil.alertSimpleMessage("预览失败", "加载读取到的图片失败", "关闭");
        }
    }
    
    /**
     * 重命名补丁文件
     */
    public void renameFile(){
        if(!enableFile.exists() && !disableFile.exists()){
            MessageUtil.alertSimpleMessage("错误", "该补丁文件已不存在", "关闭");
            MainController.getInstance().loadNPK();
            return;
        }
        MessageUtil.alertInputMessage("输入:", "输入要修改的补丁名称\n\n注: 某些加密补丁修改名称后可能会无法使用!", name, "确定", "取消", str -> {
            if(str.trim().length()==0){
                MessageUtil.alertSimpleMessage("错误", "补丁名称不能为空", "关闭");
            }else{
                String newname = str.trim();
                String enname = newname+suffix;
                String diname = enname+".disable";
                File enfile = new File(App.getFolder(), enname);
                File disfile = new File(App.getFolder(), diname);
                if(enfile.exists() || disfile.exists()){
                    MessageUtil.alertSimpleMessage("错误", "目标补丁名称已存在", "关闭");
                }else{
                    updateStatus();
                    boolean res;
                    if(status){
                        res = enableFile.renameTo(enfile);
                    }else{
                        res = disableFile.renameTo(disfile);
                    }
                    if(res){
                        MessageUtil.alertSimpleMessage("成功", "补丁文件名修改成功", "关闭");
                    }else{
                        MessageUtil.alertSimpleMessage("错误", "补丁文件名修改失败", "关闭");
                    }
                    MainController.getInstance().loadNPK();
                }
            }
        });
    }
    
    public boolean deleteFile(){
        enableFile.delete();
        disableFile.delete();
        return !enableFile.exists() && !disableFile.exists();
    }
    
    public boolean isValidate(){
        return validate;
    }
    
    public void updateStatus(){
        status = enableFile.exists();
    }
    
}